{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Linear Regression Example\n",
    "\n",
    "Linear regression implementation with TensorFlow v2 library.\n",
    "\n",
    "This example is using a low-level approach to better understand all mechanics behind the training process.\n",
    "\n",
    "- Author: Aymeric Damien\n",
    "- Project: https://github.com/aymericdamien/TensorFlow-Examples/"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from __future__ import absolute_import, division, print_function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "import numpy as np\n",
    "rng = np.random"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Parameters.\n",
    "learning_rate = 0.01\n",
    "training_steps = 1000\n",
    "display_step = 50"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Training Data.\n",
    "X = np.array([3.3,4.4,5.5,6.71,6.93,4.168,9.779,6.182,7.59,2.167,\n",
    "              7.042,10.791,5.313,7.997,5.654,9.27,3.1])\n",
    "Y = np.array([1.7,2.76,2.09,3.19,1.694,1.573,3.366,2.596,2.53,1.221,\n",
    "              2.827,3.465,1.65,2.904,2.42,2.94,1.3])\n",
    "n_samples = X.shape[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Weight and Bias, initialized randomly.\n",
    "W = tf.Variable(rng.randn(), name=\"weight\")\n",
    "b = tf.Variable(rng.randn(), name=\"bias\")\n",
    "\n",
    "# Linear regression (Wx + b).\n",
    "def linear_regression(x):\n",
    "    return W * x + b\n",
    "\n",
    "# Mean square error.\n",
    "def mean_square(y_pred, y_true):\n",
    "    return tf.reduce_sum(tf.pow(y_pred-y_true, 2)) / (2 * n_samples)\n",
    "\n",
    "# Stochastic Gradient Descent Optimizer.\n",
    "optimizer = tf.optimizers.SGD(learning_rate)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Optimization process. \n",
    "def run_optimization():\n",
    "    # Wrap computation inside a GradientTape for automatic differentiation.\n",
    "    with tf.GradientTape() as g:\n",
    "        pred = linear_regression(X)\n",
    "        loss = mean_square(pred, Y)\n",
    "\n",
    "    # Compute gradients.\n",
    "    gradients = g.gradient(loss, [W, b])\n",
    "    \n",
    "    # Update W and b following gradients.\n",
    "    optimizer.apply_gradients(zip(gradients, [W, b]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "step: 50, loss: 0.128538, W: 0.380431, b: -0.114308\n",
      "step: 100, loss: 0.122636, W: 0.372843, b: -0.060507\n",
      "step: 150, loss: 0.117408, W: 0.365701, b: -0.009876\n",
      "step: 200, loss: 0.112779, W: 0.358980, b: 0.037773\n",
      "step: 250, loss: 0.108678, W: 0.352655, b: 0.082613\n",
      "step: 300, loss: 0.105047, W: 0.346703, b: 0.124812\n",
      "step: 350, loss: 0.101831, W: 0.341101, b: 0.164524\n",
      "step: 400, loss: 0.098983, W: 0.335830, b: 0.201896\n",
      "step: 450, loss: 0.096461, W: 0.330869, b: 0.237067\n",
      "step: 500, loss: 0.094227, W: 0.326201, b: 0.270165\n",
      "step: 550, loss: 0.092249, W: 0.321807, b: 0.301313\n",
      "step: 600, loss: 0.090496, W: 0.317672, b: 0.330625\n",
      "step: 650, loss: 0.088945, W: 0.313781, b: 0.358211\n",
      "step: 700, loss: 0.087570, W: 0.310120, b: 0.384171\n",
      "step: 750, loss: 0.086353, W: 0.306674, b: 0.408601\n",
      "step: 800, loss: 0.085275, W: 0.303431, b: 0.431592\n",
      "step: 850, loss: 0.084321, W: 0.300379, b: 0.453229\n",
      "step: 900, loss: 0.083475, W: 0.297507, b: 0.473590\n",
      "step: 950, loss: 0.082727, W: 0.294804, b: 0.492752\n",
      "step: 1000, loss: 0.082064, W: 0.292260, b: 0.510785\n"
     ]
    }
   ],
   "source": [
    "# Run training for the given number of steps.\n",
    "for step in range(1, training_steps + 1):\n",
    "    # Run the optimization to update W and b values.\n",
    "    run_optimization()\n",
    "    \n",
    "    if step % display_step == 0:\n",
    "        pred = linear_regression(X)\n",
    "        loss = mean_square(pred, Y)\n",
    "        print(\"step: %i, loss: %f, W: %f, b: %f\" % (step, loss, W.numpy(), b.numpy()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Graphic display\n",
    "plt.plot(X, Y, 'ro', label='Original data')\n",
    "plt.plot(X, np.array(W * X + b), label='Fitted line')\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
